// Copyright (C) 2024 Kumo inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <merak/taskflow.h>
#include <functional>

namespace merak {

    class ThreadPool {
    public:
        ThreadPool(int32_t num_thread = 4);

        ~ThreadPool() = default;

        merak::Future<void> async(Taskflow &f);

        merak::Future<void> async(Taskflow &&f);

        merak::Future<void> async(std::function<void()> &&f);

        template<typename R>
        R run(std::function<R()> &&f);

    private:
        Executor _executor;
    };

    inline ThreadPool::ThreadPool(int32_t num_thread) : _executor(num_thread) {}

    inline merak::Future<void> ThreadPool::async(Taskflow &f) {
        return _executor.run(f);
    }

    inline merak::Future<void> ThreadPool::async(Taskflow &&f) {
        return _executor.run(std::forward<Taskflow>(f));
    }

    inline merak::Future<void> ThreadPool::async(std::function<void()> &&f) {
        Taskflow flow;
        flow.emplace(std::forward<std::function<void()>>(f));
        return _executor.run(std::forward<Taskflow>(flow));
    }

    template<typename R>
    inline R ThreadPool::run(std::function<R()> &&f) {
        R r;
        auto func = [&r, f]() {
            auto ff = std::move(f);
            r = ff();
        };
        Taskflow flow;
        flow.emplace(std::forward<std::function<void()>>(func));
        _executor.run(std::forward<Taskflow>(flow)).wait();
        return r;
    }

}  // namespace merak
